#ifndef CTRLREGISTERHELPER
#define CTRLREGISTERHELPER

#include <windows.h>
#include <vector>
using std::vector;

class HelperAddInBase
{
public:
	virtual void OnInit() {}
	virtual void OnDestroy() {}
};

struct CtrlObject
{
	void* ctrl;
	HWND hWnd;
};


template <typename T, typename AddIn = HelperAddInBase>
class CtrlRegisterHelper
{
public:
	CtrlRegisterHelper(wchar_t* ClassName);
	~CtrlRegisterHelper();

	static T* FindObject(HWND hWnd);
	static void AddObject(HWND hWnd, T* pObj);
	static void RemoveObject(HWND hWnd);
	static bool Exist();
	static LRESULT CALLBACK ControlProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
private:
	static vector<CtrlObject> ctrls;
	static AddIn addIn;
};

template <typename T, typename AddIn>
vector<CtrlObject> CtrlRegisterHelper<T, AddIn>::ctrls;

template <typename T, typename AddIn>
AddIn CtrlRegisterHelper<T, AddIn>::addIn;

template <typename T, typename AddIn>
T* CtrlRegisterHelper<T, AddIn>::FindObject(HWND hWnd)
{
	typedef vector<CtrlObject>::iterator VI;
	for(VI vi = ctrls.begin(); vi != ctrls.end(); vi++)
	{
		if(vi->hWnd == hWnd)
		{
			return (T*)(vi->ctrl);
		}
	}
	return NULL;
}

template <typename T, typename AddIn>
void CtrlRegisterHelper<T, AddIn>::AddObject(HWND hWnd, T* control)
{
	CtrlObject co;
	co.hWnd = hWnd;
	co.ctrl = control;
	control->hWnd = hWnd;
	ctrls.push_back(co);
}

template <typename T, typename AddIn>
void CtrlRegisterHelper<T, AddIn>::RemoveObject(HWND hWnd)
{
	if(IsWindow(hWnd))
	{
		DestroyWindow(hWnd);
	}

	typedef vector<CtrlObject>::iterator VI;
	for(VI vi = ctrls.begin(); vi != ctrls.end(); vi++)
	{
		if(vi->hWnd == hWnd)
		{
			ctrls.erase(vi);
			return;
		}
	}
}

template <typename T, typename AddIn>
LRESULT CALLBACK CtrlRegisterHelper<T, AddIn>::ControlProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	T* control = FindObject(hWnd);

	if(control == NULL)
	{
		control = (T*)((LPCREATESTRUCT)lParam)->lpCreateParams;
		AddObject(hWnd, control);
	}
	return control->OnMessage(iMessage, wParam, lParam);
}

template <typename T, typename AddIn>
CtrlRegisterHelper<T, AddIn>::CtrlRegisterHelper(wchar_t* ClassName)
{
	WNDCLASS WndClass;

	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hbrBackground = NULL;
	WndClass.hCursor = LoadCursor(NULL,IDC_IBEAM);
	WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
	WndClass.hInstance = GetModuleHandle(NULL);
	WndClass.lpfnWndProc = (WNDPROC)ControlProc;
	WndClass.lpszClassName = ClassName;
	WndClass.lpszMenuName = NULL;
	WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	RegisterClass(&WndClass);

	addIn.OnInit();
}

template <typename T, typename AddIn>
CtrlRegisterHelper<T, AddIn>::~CtrlRegisterHelper()
{
	addIn.OnDestroy();
}

template <typename T, typename AddIn>
bool CtrlRegisterHelper<T, AddIn>::Exist()
{
	return ctrls.size() != 0;
}

#endif //CTRLREGISTERHELPER